/*
 * Copyright 2025 arisgo@163.com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.arisgo.cloud.auth.login.granter.impl;

import com.alibaba.fastjson.JSON;
import com.arisgo.cloud.auth.login.granter.AbstractLoginGranter;
import com.arisgo.cloud.auth.login.granter.GranterStore;
import com.arisgo.cloud.auth.login.granter.configurer.ManagerConfigurer;
import com.arisgo.cloud.auth.login.model.Login;
import com.arisgo.cloud.auth.login.model.Type;
import com.arisgo.cloud.auth.sys.service.TenantService;
import com.arisgo.cloud.auth.sys.service.UserService;
import com.arisgo.cloud.auth.sys.vo.UserVo;
import com.arisgo.cloud.common.utils.AssertUtil;
import com.arisgo.cloud.common.utils.CipherUtil;
import com.arisgo.cloud.core.redis.UserInfo;
import com.arisgo.cloud.core.token.TokenGenerator;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.Base64;

/**
 * 账户密码登陆
 *
 * @author Arisgo
 * @since 2024/5/28
 */
@Component
public class PasswordGranter extends AbstractLoginGranter implements InitializingBean {

    private final UserService userService;

    private final ManagerConfigurer managerConfigurer;

    public PasswordGranter(RedisTemplate<String, Object> redisTemplate, TokenGenerator tokenGenerator,
                           TenantService tenantService, UserService userService, ManagerConfigurer managerConfigurer) {
        super(redisTemplate, tokenGenerator, tenantService);
        this.userService = userService;
        this.managerConfigurer = managerConfigurer;
    }

    @Override
    protected UserInfo checkLogin(Login login) {
        // 验证码校验
        checkCaptcha(login.getCaptcha());

        AssertUtil.hasLength(login.getUsername(), "账号为空！");
        AssertUtil.hasLength(login.getCertificate(), "密码为空！");

        // 登陆验证
        return managerConfigurer.getAccount().equals(login.getUsername()) ? adminLogin(login) : userLogin(login);
    }

    /**
     * 超级管理员登陆
     *
     * @param login 登陆用户信息
     * @return 登陆用户
     */
    private UserInfo adminLogin(Login login) {
        logger.info("超级管理员登陆！");
        String password = CipherUtil.encode(new String(Base64.getDecoder().decode(login.getCertificate())), managerConfigurer.getEncipher());
        AssertUtil.isTrue(managerConfigurer.getPassword().equals(password), "密码错误");

        // 登录信息
        UserInfo userInfo = new UserInfo();
        userInfo.setUserId(managerConfigurer.getUserId());
        userInfo.setUsername(managerConfigurer.getAccount());
        userInfo.setNickname(managerConfigurer.getNickname());
        userInfo.setTenantId(managerConfigurer.getTenantId());
        userInfo.setTenantName(managerConfigurer.getTenantName());
        userInfo.setStaffId(0L);
        userInfo.setOwner(true);
        logger.info("账号信息：{}", JSON.toJSONString(userInfo));
        return userInfo;
    }

    /**
     * 普通用户登陆
     *
     * @param login 登陆用户信息
     * @return 登陆用户
     */
    private UserInfo userLogin(Login login) {
        // 普通用户登陆
        logger.info("普通用户登陆！");
        UserVo user = userService.findUserByAccount(login.getUsername());

        AssertUtil.notNull(user, "用户名不存在！");
        String password = new String(Base64.getDecoder().decode(login.getCertificate()));
        AssertUtil.isTrue(CipherUtil.SHA.encode(password).equals(user.getPassword()), "密码错误！");

        if (user.getStatus().equals(-1)) {
            user.setStatus(0);
            userService.save(user);
        } else if (user.getStatus().equals(1) || user.getStatus().equals(2)) {
            // TODO 2025-03-15 检测是否达到解封时间
            // 1. 达到时间，更新状态为正常，正常登陆
            // 2. 不到时间，直接抛出异常
            throw new RuntimeException("已被封号，不能登陆！");
        }

        // 登录信息
        UserInfo userInfo = new UserInfo();
        BeanUtils.copyProperties(user, userInfo);
        userInfo.setUserId(user.getId());
        userInfo.setUsername(user.getAccount());
        userInfo.setTenantId(user.getTenantId());
        userInfo.setStaffId(user.getStaffId());

        logger.info("账号信息：{}", JSON.toJSONString(userInfo));
        return userInfo;
    }

    @Override
    protected void findTenant(UserInfo user) {
        if (!managerConfigurer.getUserId().equals(user.getUserId())) {
            super.findTenant(user);
        } else {
            // 超级管理员，无role，无staff，一切必要的展示，在配置文件中配置即可
            logger.info("super admin login!");
        }
    }

    @Override
    public boolean register(Login login) {
        checkCaptcha(login.getCaptcha());
        AssertUtil.isTrue(!userService.isExistsUser(login.getUsername()), "用户名已存在！");

        UserVo user = new UserVo();
        user.setAccount(login.getUsername());
        user.setNickname(login.getUsername());
        user.setPassword(CipherUtil.SHA.encode(new String(Base64.getDecoder().decode(login.getCertificate()))));
        userService.save(user);
        return true;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        GranterStore.register(Type.PASSWORD.name(), this);
    }

}
